package com.example.framework;

import com.example.annotation.GQAutoWired;
import com.example.annotation.GQComponent;
import com.example.annotation.GQController;
import com.example.business.service.ExtendsService02;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;

public class GQApplicationContext {
    private List<String> classNameList = new ArrayList<>();
    private Map<String, Object> instanceMap = new ConcurrentHashMap<>();
    private String pathScan = "com.example.business";
    private String templatePath = "layouts";
    private String replace = "";

    public GQApplicationContext() {
        try {
            replace = pathScan.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
            URL path = GQApplicationContext.class.getClassLoader().getResource(Matcher.quoteReplacement(File.separator) + replace);
            String realPath = java.net.URLDecoder.decode(path.getPath(), "utf-8");

            // 获取 class 文件
            register(realPath, classNameList);
            // 注册
            doCreateBean();
            // 注入
            populate();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        ExtendsService02 extendsService02 = (ExtendsService02) instanceMap.get("extendsService02");
        extendsService02.a();
    }

    /**
     * 根据指定报名扫描bean  并且缓存
     *
     * @param path
     * @throws UnsupportedEncodingException
     */
    private void register(String path, List<String> list) {
        List<File> parentList = new ArrayList<>();
        getAllFile(path, parentList);
        for (File file : parentList) {
            String fileClassPath = file.getPath().substring(file.getPath().indexOf(replace));
            String realFilePath = fileClassPath.replace(File.separator, ".");
            list.add(realFilePath.replace(".class", ""));
        }
    }

    /**
     * 初始化ioc容器
     *
     * @throws Exception
     */
    private void doCreateBean() throws Exception {
        for (String className : classNameList) {
            Class<?> aClass = Class.forName(className);
            Annotation[] annotations = aClass.getAnnotations();
            if (aClass.isAnnotationPresent(GQComponent.class) || aClass.isAnnotationPresent(GQController.class)) {
                String id = lowerFirstChar(aClass.getSimpleName());
                instanceMap.put(id, aClass.newInstance());
            }
        }
    }

    /**
     * 注入
     */
    private void populate() {
        if (instanceMap.isEmpty()) {
            return;
        }
        for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
            Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                if (!field.isAnnotationPresent(GQAutoWired.class)) {
                    continue;
                }
                GQAutoWired annotation = field.getAnnotation(GQAutoWired.class);
                String id = annotation.value().trim();
                // 如果 ID 为空，就根据类型来注入
                if ("".equals(id)) {
                    id = field.getType().getName();
                }
                field.setAccessible(true); // 把私有变量开放访问权限
                try {
                    field.set(entry.getValue(), instanceMap.get(id));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @param path 获取给定路径下面的全部路径
     * @param list
     * @throws UnsupportedEncodingException
     */
    public void getAllFile(String path, List<File> list) {
        File parentDir = new File(path);
        for (File file : parentDir.listFiles()) {
            if (file.isDirectory()) {
                getAllFile(file.getPath(), list);
            } else {
                list.add(file);
            }
        }
    }

    /**
     * 首字母小写
     *
     * @param string
     * @return
     */
    private String lowerFirstChar(String string) {
        char[] chars = string.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    /**
     * 将 ioc 容器 放给外界
     *
     * @return
     */
    public Map<String, Object> getAll() {
        return instanceMap;
    }

    /**
     * 将模板路径放出去
     *
     * @return
     */
    public String getTemplatePath() {
        return templatePath;
    }
}
